# coding=utf-8
import datetime
import time
import calendar
from decimal import Decimal


class Timer(object):
    __time_unit = {
        "s": 1,
        "ms": 1000,
        "us": 1000000,
    }

    def __init__(self, unit="s", precision=4):
        self.start = None
        self.end = None
        self.total = 0
        self.unit = unit
        self.precision = precision

    def __str__(self):
        return 'Running time: {}{}'.format(self.total, self.unit)

    def __enter__(self):
        if self.unit not in Timer.__time_unit:
            raise KeyError('Unsupported time unit.')
        self.start = time.time()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.end = time.time()
        self.total = (self.end - self.start) * Timer.__time_unit[self.unit]
        self.total = round(self.total, self.precision)
        print(self)


def format_date(dt, dt_format="%Y-%m-%d"):
    if not isinstance(dt, datetime.datetime):
        raise TypeError("{} is not of datetime".format(dt))
    return dt.strftime(dt_format)


def format_datetime(dt, dt_format="%Y-%m-%d %H:%M:%S"):
    if not isinstance(dt, datetime.datetime):
        raise TypeError("{} is not of datetime".format(dt))
    return dt.strftime(dt_format)


def get_today_date(now=datetime.datetime.now()):
    zero_today = now - datetime.timedelta(hours=now.hour, minutes=now.minute, seconds=now.second)
    last_today = zero_today + datetime.timedelta(hours=23, minutes=59, seconds=59)
    return zero_today, last_today


def get_3today_date(now=datetime.datetime.now()):
    zero_today = now - datetime.timedelta(days=2, hours=now.hour, minutes=now.minute, seconds=now.second)
    last_today = zero_today + datetime.timedelta(days=2, hours=23, minutes=59, seconds=59)
    return zero_today, last_today


def get_7today_date(days,now=datetime.datetime.now()):
    zero_today = now - datetime.timedelta(days=days, hours=now.hour, minutes=now.minute, seconds=now.second)
    last_today = zero_today + datetime.timedelta(days=days, hours=23, minutes=59, seconds=59)
    return zero_today, last_today


def dt2str(dt, dt_format="%Y-%m-%d %H:%M:%S"):
    if not isinstance(dt, datetime.datetime):
        raise TypeError("{} is not of datetime".format(dt))
    return dt.strftime(dt_format)


def str2dt(dt_str, dt_format="%Y-%m-%d %H:%M:%S"):
    return datetime.datetime.strptime(dt_str, dt_format)


def now():
    # print(datetime.datetime.now())
    return datetime.datetime.now()


def ts():
    return int(time.mktime(datetime.datetime.now().timetuple()))


def now_str():
    return format_datetime(now())


def dt2ts(dt):
    return time.mktime(dt.timetuple()) if dt else None


def ts2dt(ts):
    return datetime.datetime.fromtimestamp(ts)


def mouth_last_day():
    last_day_list = []
    now_year = now().year
    a1 = [now_year - 1, now_year]
    a2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
    # 计算两年前的最后一天
    day = calendar.monthrange(now_year - 2, 12)[1]
    str0 = str(now_year - 2) + "-" + str(12).rjust(2, '0') + "-" + str(day) + " 12:59:59"
    last_day_list.append(str0)
    for i in a1:
        for j in a2:
            day = calendar.monthrange(i, j)[1]
            str_day = str(i) + "-" + str(j).rjust(2, '0') + "-" + str(day) + " 12:59:59"
            last_day_list.append(str_day)
    return last_day_list


def float_number(number):
    return '%.2f' % number


def get_month_start_and_end_by_date_interval(year):
    """
    获取指定时间段内每个月的起止时间参数列表
    :param start_date: 起始时间 --> str
    :param end_date: 结束时间 --> str
    :return: date_range_list -->list [{'2019-10-01': ['2019-10-01', '2019-10-31']}, ...}]

    """
    date_range_list = []
    # start_time = datetime.datetime(2020, 9, 23, 0, 0),
    start_date = '{}-1-01 00:00:00'.format(year)
    end_date = '{}-12-01 23:59:59'.format(year)
    start_date = datetime.datetime.strptime(start_date, '%Y-%m-%d %H:%M:%S')
    end_date = datetime.datetime.strptime(end_date, '%Y-%m-%d %H:%M:%S')
    # 计算开始日期的当月起止日期
    start_month_first = datetime.datetime(year=start_date.year, month=start_date.month, day=1, hour=0, minute=0,
                                          second=0).date()

    start_month_last = datetime.datetime(year=start_date.year, month=start_date.month,
                                         day=calendar.monthrange(start_date.year, start_date.month)[1], hour=23,
                                         minute=end_date.minute,
                                         second=end_date.second).date()

    date_range_list.append([start_month_first.strftime('%Y-%m-%d'), start_month_last.strftime('%Y-%m-%d')])

    # 计算结束日期的当月起止日期
    end_month_first = datetime.datetime(year=end_date.year, month=end_date.month, day=1, hour=0, minute=0,
                                        second=0).date()

    end_month_last = datetime.datetime(year=end_date.year, month=end_date.month,
                                       day=calendar.monthrange(end_date.year, end_date.month)[1], hour=end_date.hour,
                                       minute=end_date.minute,
                                       second=end_date.second).date()

    while True:
        # 下个月开始日期
        next_month_start = datetime.datetime(year=start_date.year, month=start_date.month,
                                             day=calendar.monthrange(start_date.year, start_date.month)[
                                                 1], hour=0, minute=0,
                                             second=0).date() + datetime.timedelta(days=1)

        next_month_end = datetime.datetime(year=next_month_start.year, month=next_month_start.month,
                                           day=calendar.monthrange(next_month_start.year, next_month_start.month)[
                                               1], hour=end_date.hour, minute=end_date.minute,
                                           second=end_date.second).date()

        if next_month_start < end_month_first:
            date_range_list.append([next_month_start.strftime('%Y-%m-%d'), next_month_end.strftime('%Y-%m-%d')])
            start_date = next_month_start
        else:
            break
    # 避免传入的起止日期在同一月导致数据重复
    temp_dict = [end_month_first.strftime('%Y-%m-%d'), end_month_last.strftime('%Y-%m-%d')]
    if temp_dict not in date_range_list:
        date_range_list.append(temp_dict)

    for i in date_range_list:
        i[0] = str(i[0] + " 00:00:00")
        i[1] = str(i[1] + " 23:59:59")

    return date_range_list


def day_get():
    d = datetime.datetime.now()
    # d = datetime.datetime(2018, 11, 20, 0, 0)
    day_list = []
    for i in range(1, 7):
        oneday = datetime.timedelta(days=i)
        day = d - oneday
        date_to = datetime.datetime(day.year, day.month, day.day)
        date_end = datetime.datetime(day.year, day.month, day.day, hour=23, minute=59, second=59)
        day_list.insert(0, (str(date_to), str(date_end)))
    now_to = datetime.datetime(d.year, d.month, d.day)
    d = format_datetime(d)
    day_list.append((str(now_to), str(d)))
    return day_list


def get_two_week_date(days):
    day_list = []
    for i in range(days):
        today = datetime.date.today() + datetime.timedelta(days=i)
        day_list.append(today.strftime("%Y-%m-%d"))

    return day_list
